#ifdef _WINDOWS
#include <Windows.h>
#endif

#include <gl/glew.h>
#include "sound.h"
#include "input.h"
#include <vector.h>

#ifdef _DEBUG
#include <cstdio>
#endif

#ifdef _WINDOWS

LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wcex.lpfnWndProc = WindowProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = NULL;
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = "mppvpmgruntime";
	wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	
	if(!RegisterClassEx(&wcex))
		return 1;
	
	Vector2i windowSize;
	windowSize.x = GetSystemMetrics(SM_CXSCREEN);
	windowSize.y = GetSystemMetrics(SM_CYSCREEN);

	DEVMODE fullscreen;
	memset(&fullscreen, 0, sizeof(fullscreen));
	fullscreen.dmSize = sizeof(fullscreen);
	fullscreen.dmPelsWidth = windowSize.x;
	fullscreen.dmPelsHeight = windowSize.y;
	fullscreen.dmBitsPerPel = 3;
	fullscreen.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

	if(!ChangeDisplaySettings(&fullscreen, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
		return 1;

	HWND hwnd = CreateWindowEx(	WS_EX_APPWINDOW, "mppvpmgruntime", "MultiPlayer PvP Mini Game Runtime",
								WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
								0, 0, windowSize.x, windowSize.y,
								NULL, NULL, hInstance, NULL);
	ShowWindow(hwnd, nCmdShow);
	ShowCursor(FALSE);

	HDC hDC = GetDC(hwnd);
	PIXELFORMATDESCRIPTOR pfd;
	ZeroMemory(&pfd, sizeof(pfd));
	pfd.nSize = sizeof(pfd);
	pfd.nVersion = 1;
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
	pfd.iPixelType = PFD_TYPE_RGBA;
	pfd.cColorBits = 24;
	pfd.cDepthBits = 16;
	pfd.iLayerType = PFD_MAIN_PLANE;
	int format = ChoosePixelFormat(hDC, &pfd);
	SetPixelFormat(hDC, format, &pfd);
	HGLRC hRC = wglCreateContext(hDC);
	wglMakeCurrent(hDC, hRC);

	glewInit();

	if(!GLEW_VERSION_3_1) {
		MessageBox(hwnd, "OpenGL version 3.1 not supported!", "Error", MB_OK | MB_ICONERROR);
	}

	glLoadIdentity();
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, windowSize.x, windowSize.y, 0, -1, 1);

	ALfloat listenerPos[] = {0.0f, 0.0f, 0.0f};
	ALfloat listenerVel[] = {0.0f, 0.0f, 0.0f};
	ALfloat listenerOri[] = {0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f};
	Sound::SetListenerPosition(listenerPos);
	Sound::SetListenerVelocity(listenerVel);
	Sound::SetListenerOrientation(listenerOri);

	Input* input = new Input();
	if(!input->Init(hInstance, hwnd, windowSize))
		input = NULL;

	MSG msg;
	Vector2i cursorPos;
	cursorPos.x = 0;
	cursorPos.y = 0;
	bool run = true;
	while(run)
	{
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if(msg.message == WM_QUIT)
				run = false;
			else
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
		else
		{
			glClear(GL_COLOR_BUFFER_BIT);

			glColor3f(1.0f, 0.0f, 1.0f);

			glBegin(GL_QUADS);
				glVertex2f(cursorPos.x - 4, cursorPos.y - 4);
				glVertex2f(cursorPos.x + 4, cursorPos.y - 4);
				glVertex2f(cursorPos.x + 4, cursorPos.y + 4);
				glVertex2f(cursorPos.x - 4, cursorPos.y + 4);
			glEnd();

			SwapBuffers(hDC);

			if(input != NULL) {
				if(input->PollInput()) {
					unsigned char* keys = input->GetKeyboardState();
					if(keys[DIK_ESCAPE] & DICONST)
						run = false;
#ifdef _DEBUG
					if(keys[DIK_SPACE] & DICONST) {
						char* cursorPosString;
						std::sprintf(cursorPosString, "x=%i;y=%i", cursorPos.x, cursorPos.y);
						MessageBox(hwnd, cursorPosString, "DEBUG", MB_OK | MB_ICONASTERISK);
					}
#endif
					cursorPos.x = input->GetMousePos().x;
					cursorPos.y = input->GetMousePos().y;
				}
			}
		}
	}

	if(input != NULL)
		input->Destroy();

	alutExit();

	wglMakeCurrent(NULL, NULL);
	wglDeleteContext(hRC);
	ReleaseDC(hwnd, hDC);

	ChangeDisplaySettings(NULL, 0);
	ShowCursor(TRUE);
	DestroyWindow(hwnd);
	UnregisterClass("mppvpmgruntime", hInstance);

	return msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_CLOSE:
		PostQuitMessage(0);
		break;
	case WM_DESTROY:
		return 0;
	default:
		return DefWindowProc(hwnd, uMsg, wParam, lParam);
	}

	return 0;
}

#elif _LINUX

#define HERE_COULD_BE_YOUR_DEFINITION

#endif